package org.xxpay.pay.channel.zealchin;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.xxpay.common.http.HttpRequestTemplate;
import org.xxpay.common.util.HtmlUtils;
import org.xxpay.common.util.sign.SignUtils;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.common.util.AmountUtil;
import org.xxpay.core.entity.PayOrder;
import org.xxpay.pay.channel.BasePayment;
import org.xxpay.pay.channel.yipay.YipayConfig;
import org.xxpay.pay.channel.zhifu.ZhifuConfig;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import static com.alibaba.dubbo.common.Constants.INTERFACE_KEY;

@Service
public class ZealchinPaymentService extends BasePayment {

    private final static String logPrefix = "【ZEALCHIN】";

    @Override
    public String getChannelName() {
        return ZealchinConfig.CHANNEL_NAME;
    }

    @Override
    public JSONObject pay(PayOrder payOrder) {
        String channelId = payOrder.getChannelId();
        JSONObject retObj;
        switch (channelId) {
            case ZealchinConfig.CHANNEL_NAME_ZEALCHIN_ALIPAY:
                retObj = doOrderReq(payOrder);
                break;
            default:
                retObj = buildRetObj(PayConstant.RETURN_VALUE_FAIL, "不支持的渠道[channelId="+channelId+"]");
                break;
        }
        return  retObj;
    }

    /**
     * 查询订单
     * @param payOrder
     * @return
     */
    @Override
    public JSONObject query(PayOrder payOrder) {
        ZealchinConfig config = new ZealchinConfig(getPayParam(payOrder));
        String payOrderId = payOrder.getPayOrderId();
        _log.info("{}开始查询易付通道订单,payOrderId={}", logPrefix, payOrderId);
        Map<String,Object> parameters = Maps.newHashMap();
        parameters.put("member_id", config.getAppId());
        parameters.put("order_no", payOrderId);
        parameters.put("sign", getSign(parameters, config.getPrivateKey()));
        HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
        JSONObject origin = requestTemplate.postForObject(config.getRequestUrl()+ZealchinConfig.REQ_PAY_QUERY_URL_FIXX, parameters, JSONObject.class);
        _log.info("{}易付查单同步请求响应参数：{}", logPrefix, origin.toJSONString());
        // 响应对象
        JSONObject retObj = new JSONObject();
        if(StringUtils.equals(origin.getString("status"), "1")) {
            JSONObject info = JSONObject.parseObject(origin.getString("info"));
            // 易付订单支付状态：1-为已⽀支付，其它未⽀支付
            String payStatus = info.getString("order_status");
            // 已支付
            if(StringUtils.equals("1", payStatus)) {
                retObj.put("status", 2);
            } else {
                // 支付中
                retObj.put("status", 1);
            }
            retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_SUCCESS);
            retObj.put("channelOrderNo", info.getString("order_no"));
            retObj.put("channelObj", origin.toJSONString());
            return retObj;
        }
        retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_FAIL);
        retObj.put(PayConstant.RESULT_PARAM_ERRDES, origin.getString("msg"));
        return retObj;
    }

    //下单请求实现
    private JSONObject doOrderReq(PayOrder payOrder){
        ZealchinConfig config = new ZealchinConfig(getPayParam(payOrder));
        String payType = config.getPayMode();
        Map<String,Object> parameters = Maps.newHashMap();
        setParams(parameters,payOrder,config,payType);
        _log.info("{}请求数据:{}", getChannelName(), JSON.toJSONString(parameters));
        // 将订单改为支付中
        rpcCommonService.rpcPayOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);

        HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
        JSONObject origin = requestTemplate.postForObject(config.getRequestUrl()+ZealchinConfig.REQ_PAY_QUERY_URL_FIXX, parameters, JSONObject.class);
        _log.info("{}返回数据:{}", getChannelName(), JSON.toJSONString(origin));
        JSONObject retObj = new JSONObject();
        String payForm = getHtml(origin.getString("pay_url"));
        return buildPayResultOfForm(retObj, payOrder, payForm);
    }

    /**
     * 设置支付请求参数
     * @param map
     * @param payOrder
     * @param config
     */
    private void setParams(Map<String,Object> map, PayOrder payOrder, ZealchinConfig config, String payType){
        map.put("order_no", payOrder.getPayOrderId());
        map.put("money", AmountUtil.convertCent2Dollar(String.valueOf(payOrder.getAmount())));
        map.put("member_id", config.getAppId());
        map.put("channel_id", payType);
        map.put("jump","0");
        map.put("notify_url", payConfig.getNotifyUrl(getChannelName()));
        map.put("redirect_url", payOrder.getReturnUrl());
        map.put("sign", getSign(map, config.getPrivateKey()));
    }

    /**
     * 获取签名
     *
     * @param params 签名参数
     * @return sign
     */
    private static String getSign(Map<String, Object> params,String key) {

        // 先将参数以其参数名的字典序升序进行排序
        Map<String, Object> sortedParams = new TreeMap<String, Object>(params);
        Set<Map.Entry<String, Object>> entrys = sortedParams.entrySet();

        // 遍历排序后的字典，将所有参数按"valuevaluevalue"格式拼接在一起
        StringBuilder basestring = new StringBuilder();
        for (Map.Entry<String, Object> param : entrys) {
            basestring.append(param.getValue());
        }
        basestring.append(key);
        // 使用MD5对待签名串求签
        byte[] bytes = null;
        MessageDigest md5;
        try {
            md5 = MessageDigest.getInstance("MD5");
            bytes = md5.digest(basestring.toString().getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // 将MD5输出的二进制结果转换为小写的十六进制
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex);
        }
        return sign.toString();
    }

    //获取请求html
    private String getHtml(String payUrl){
        StringBuffer buffer = new StringBuffer();
        buffer.append("<script type=\"text/javascript\">");
        buffer.append("window.location.href=\""+payUrl+"\"");
        buffer.append("</script>");
        return buffer.toString();
    }

}
